﻿using System;
using System.Web;
using System.Web.Mvc;
using Motar.Web.Mvc.Properties;

namespace Motar.Web.Mvc
{

    /// <summary>
    /// 
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public abstract class AuthorizeAttributeBase : FilterAttribute, IAuthorizationFilter
    {

        /// <summary>
        /// 
        /// </summary>
        private readonly object _typeId = new object();

        /// <summary>
        /// 
        /// </summary>
        public override object TypeId
        {
            get { return _typeId; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filterContext"></param>
        public virtual void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
            {
                throw new InvalidOperationException(Resources.AuthorizeAttributeBase_CannotUseWithinChildActionCache);
            }

            if (Authorize(filterContext.HttpContext))
            {
                HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;

                cachePolicy.SetProxyMaxAge(new TimeSpan(0));

                cachePolicy.AddValidationCallback(HandleCacheValidation, null);
            }
            else
            {
                HandleUnauthorizedRequest(filterContext);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        protected abstract bool Authorize(HttpContextBase httpContext);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        /// <param name="data"></param>
        /// <param name="validationStatus"></param>
        private void HandleCacheValidation(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }

            return Authorize(httpContext) ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filterContext"></param>
        protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }
}
